<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<title>Trinty Desktop Shell</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta name="description" content="Java Shell.">
		<meta name="author" content="Erik De Rijcke">
		<!-- Bootstrap -->
		<link href="assets/css/bootstrap.min.css" rel="stylesheet">
    <link href="assets/css/docs.css" rel="stylesheet">
    <style type="text/css">
      body {
        padding-top: 40px;
        padding-bottom: 120px;
      }
    </style>
    <!-- Pretty print-->
    <link href="assets/css/prettify.css" type="text/css" rel="stylesheet" />
	</head>
	<body onload="prettyPrint()" bgcolor="white" data-spy="scroll" data-target=".docs-sidebar">
		<div class="navbar navbar-fixed-top">
  		<div class="navbar-inner">
  			<div class="container">

  				<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
        		<span class="icon-bar"></span>
        		<span class="icon-bar"></span>
        		<span class="icon-bar"></span>
      		</a>

    			<a class="brand" href="./index.html">Trinity Shell</a>
    			<div class="nav-collapse">
    				<ul class="nav">
      				<li class="active"><a href="./developer.html">Developer</a></li>
      				<li><a href="./user.html">User</a></li>
      				<li><a href="./download.html">Download</a></li>
      				<li><a href="./about.html">About</a></li>
    				</ul>
    			</div>
  			</div>
  		</div>
		</div>
		<div class="container">
			<div class="row">
      		<!--Sidebar content-->
          <div class="span3 docs-sidebar ">
            <ul class="nav nav-list docs-sidenav sidebar-nav-fixed">
              <li><a href="#Disclaimer"><i class="icon-chevron-right"></i> Disclaimer</a></li>
              <li><a href="#Intro"><i class="icon-chevron-right"></i> Intro</a></li>
              <li><a href="#Basics"><i class="icon-chevron-right"></i> The Basics</a></li>
              <li><a href="#Clutter"><i class="icon-chevron-right"></i> Clutter</a></li>
              <li><a href="#OpenGL"><i class="icon-chevron-right"></i> OpenGL</a></li>
              <li><a href="#Outro"><i class="icon-chevron-right"></i> Outro</a></li>
            </ul>
          </div>

    			<div class="span9">
      				<!--Body content-->
            <ul class="breadcrumb">
              <li><a href="#">Developer</a> <span class="divider">/</span></li>
              <li><a href="#">Resource</a> <span class="divider">/</span></li>
              <li class="active">so you want to build a compositor</li>
            </ul>
            <section id="Disclaimer">
      				<div class="page-header" >
      					<h1>Disclaimer</h1>
      				</div>
              <p>
              The information on this page was copied from <a href="http://wingolog.org/archives/2008/07/26/so-you-want-to-build-a-compositor">here</a>. Reformatted and prettified. It handles the basic idea of how a compositor works under the X11 protocol. The code examples are in C but should be straightforward in any language. It offers a clear view on how compositing can be done with clutter under X. The article is from 2008 but is still very relevant.</p>
            </section>
            <section id="Intro">
              <div class="page-header">
                <h1>Intro</h1>
              </div>
              <h3>A dialog with someone I don't know.</h3>
              <p>
                <blockquote>
                  <p>
                    One way to think about it is that it's like driving a car down the road, and suddenly swapping the steering wheel and brakes out for a tiller and gear shifter. And having to downshift for braking until you learn that the brakes moved to the turn indicator lever. By trial and error.
                  </p>
                  <small>
                    Joey Hess 
                    <cite title="Source Title">
                      in
                      <a href="http://joeyh.name/blog/entry/awesome/"> his blog post</a>
                    </cite>
                  </small>
                </blockquote>
              </p>
              <p>
              A while back I <a href="http://wingolog.org/archives/2008/06/10/regarding-decadence">discussed some new interaction possibilities</a>, and a lot of them hinged on the relation between people and the set of tasks that they do on the computer -- not just the tasks themselves, but the relationships between the tasks, and with focus.
              </p>
              <p>In the free desktop, the locus of this experience is in the window manager. Again, Joey tries to give analogies:</p>
              <p>
                <blockquote>
                  <p>
                    Another way to look at it is adopting a new philosophy. Or, in some cases a cult. (In some cases, with crazy cult leaders.) Whether they use Windows or a Mac, or Linux, most computer users are members of a big established religion, with some implicit assumptions, like "thy windows shall be overlapping, like papers on the desktop, and thou shalt move them with thy mouse".
                  </p>
                  <small>Joey Hess</small>
                </blockquote>
              </p>
              <p>The obvious step if you want to <a href="http://www.apostasia.es/">apostatize</a> yourself from the "desktop metaphor", then, is to start hacking window managers. That's how I spent my hack-time in the last month and a half; this writing is an attempt at exegesis.</p>
            </section>
            <section id="Basics">
              <div class="page-header">
                <h1>The Basics</h1>
              </div>
              <h2>Descent from the mountain, source in hand.</h3>
              <p>I wanted to make a 3D compositing window manager. By 3D, I mean that I wanted the pixels behind the monitor glass to come entirely from one process' OpenGL. By "compositing", I mean that the graphical output from other programs should be redirected through my program. (<a href="http://en.wikipedia.org/wiki/Compositing_window_manager">Compositors</a> don't necessarily need to be implemented with OpenGL; xcompmgr and metacity's compositor are implemented with XRender.)</p>
              <h4>Hello Clutter.</h4>
              <p>As an implementation strategy, I took this opportunity to check out <a href="http://clutter-project.org/">Clutter</a>, a GL-based canvas library. What follows is a minimal translation into C of the basic concepts, a broken but fun-to-hack substrate for experimentation.</p>
              <pre class="prettyprint linenums">
int main (int argc, char *argv[])
{
    prep_clutter (&amp;argc, &amp;argv);
    prep_root ();
    prep_overlay ();
    prep_stage ();
    prep_input ();

    g_main_loop_run (g_main_loop_new (NULL, FALSE));

    return 0;
}
              </pre>
              <h4>Hello Composite</h4>
<p>The main function is pretty simple. We'll be looking at the various functions one by one, but out of order. Let's start with <code>prep_root</code>:</p>
              <pre class="prettyprint linenums">
Display *dpy;
Window root;
void prep_root (void)
{
    dpy = clutter_x11_get_default_display ();
    root = DefaultRootWindow (dpy);

    XCompositeRedirectSubwindows (dpy, root, CompositeRedirectAutomatic);
    XSelectInput (dpy, root, SubstructureNotifyMask);
}
              </pre>
              <p>This function does two things of interest: first, it tells the X server to redirect output of all windows into backing pixmaps, such that the contents of all mapped windows are available, even if the X server does not think that they are visible. Second, we ask the X server to give us notification when windows come and go, and when they change size.
              </p>
              <pre class="prettyprint linenums">
Window overlay;
void prep_overlay (void)
{
    overlay = XCompositeGetOverlayWindow (dpy, root);
    allow_input_passthrough (overlay);
}
              </pre>
              <p>
                The Composite extension, which allows us to redirect window output, also provides for the existence of an "overlay" window, one that is above all other windows. You can draw directly to the overlay window, but the normal way that you use it is as a parent window -- you create your own window, then reparent it to the overlay.
              </p>
              <p>
                Composite is pretty cool, except that it is only for output -- that is, you can put the output of a window anywhere, like on the corner of a <a href="http://en.wikipedia.org/wiki/Compiz">Compiz</a> cube, but you can't redirect input. By that I mean to say that when you have a rotated compiz cube, you can't interact with the window.
              </p>
              <p>
                The reason for this is that in order to interact with a window, for example to click a button in it, the X server needs to know how to map the pointer position to a position inside a certain window. <a href="http://lists.freedesktop.org/archives/xorg/2007-February/021515.html">This is a tricky problem</a> which needs to be done inside the X server, and no solution to this problem has been merged yet.
              </p>
              <h4>Hello XFixes</h4>
              <p>
                This upshot is that what happens today with compositing window managers is that the compositor is very careful to make sure that the underlying X window is exactly positioned behind where the compositor is drawing it. Then, when the user clicks on what essentially is the redirected image of the button, the click actually falls behind the overlay to the actual X window.
              </p>
              <p>
                Hence, the need to allow events (clicks, pointer motion, etc) to pass through the overlay:
              </p>
              <pre class="prettyprint linenums">
void allow_input_passthrough (Window w)
{
    XserverRegion region = XFixesCreateRegion (dpy, NULL, 0);
 
    XFixesSetWindowShapeRegion (dpy, w, ShapeBounding, 0, 0, 0);
    XFixesSetWindowShapeRegion (dpy, w, ShapeInput, 0, 0, region);

    XFixesDestroyRegion (dpy, region);
}
              </pre>
              <p>
                Basically we call a few undocumented functions, whose goal is to tell the X server that the window in question is not to receive pointer input events.
              </p>
            </section>
            <section id="Clutter">
              <div class="page-header">
                <h1>Clutter</h1>
              </div>
              <h4>Hello Clutter Stage</h4>
              </p>
              <p>
                The next step is to create the clutter "stage", the GLX window to which all of our output will go. We reparent the stage to the overlay, so that it will always be on top.
              </p>
              <pre class="prettyprint linenums">
void allow_input_passthrough (Window w)
{
    XserverRegion region = XFixesCreateRegion (dpy, NULL, 0);
 
    XFixesSetWindowShapeRegion (dpy, w, ShapeBounding, 0, 0, 0);
    XFixesSetWindowShapeRegion (dpy, w, ShapeInput, 0, 0, region);

    XFixesDestroyRegion (dpy, region);
}
              </pre>
              <h4>Hello Input Events</h4>
              <p>
                We allow input events to pass through it as well.
              </p>
              <pre class="prettyprint linenums">
Window input;
void prep_input (void)
{
    XWindowAttributes attr;

    XGetWindowAttributes (dpy, root, &amp;attr);
    input = XCreateWindow (dpy, root,
                           0, 0,  /* x, y */
                           attr.width, attr.height,
                           0, 0, /* border width, depth */
                           InputOnly, DefaultVisual (dpy, 0), 0, NULL);
    XSelectInput (dpy, input,
                  StructureNotifyMask | FocusChangeMask | PointerMotionMask
                  | KeyPressMask | KeyReleaseMask | ButtonPressMask
                  | ButtonReleaseMask | PropertyChangeMask);
    XMapWindow (dpy, input);
    XSetInputFocus (dpy, input, RevertToPointerRoot, CurrentTime);

    attach_event_source ();
}
              </pre>
              <p>
                So if the events fall through the stage, and fall through the overlay, what happens if they don't fall onto a window? Well, you probably want the stage to get the last crack at them, instead of the root window. So hence this terrible trick, making a separate fullscreen input-only window, located below all windows except the root window. We select for all input on this window, so that we get e.g. key presses as well.
              </p>
              <p>
                Then we install a <a href="http://library.gnome.org/devel/glib/unstable/glib-The-Main-Event-Loop.html#GSource">GSource</a> to process pending X events, redirecting events from the input window to the stage window:
              </p>
              <pre class="prettyprint linenums">
GPollFD event_poll_fd;
static GSourceFuncs event_funcs = {
    event_prepare,
    event_check,
    event_dispatch,
    NULL
};
void attach_event_source (void)
{
    GSource *source;

    source = g_source_new (&amp;event_funcs, sizeof (GSource));

    event_poll_fd.fd = ConnectionNumber (dpy);
    event_poll_fd.events = G_IO_IN;

    g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS);
    g_source_add_poll (source, &amp;event_poll_fd);
    g_source_set_can_recurse (source, TRUE);
    g_source_attach (source, NULL);
}
              </pre>
              <p>
                The <code>prepare()</code> and <code>check()</code> functions are a bit boring, but the <code>dispatch()</code> is worth a look:
              </p>
              <pre class="prettyprint linenums">
static gboolean
event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
{
    ClutterEvent *event;
    XEvent xevent;

    clutter_threads_enter ();

    while (!clutter_events_pending () &amp;&amp; XPending (dpy)) {
        XNextEvent (dpy, &amp;xevent);
        
        /* here the trickiness */
        if (xevent.xany.window == input) {
            xevent.xany.window = stage_win;
        }

        clutter_x11_handle_event (&amp;xevent);
    }
    
    if ((event = clutter_event_get ())) {
        clutter_do_event (event);
        clutter_event_free (event);
    }

    clutter_threads_leave ();

    return TRUE;
}
              </pre>
              <p>
                We just pick off events, translating the input to the stage window, then give the events to clutter.
              </p>
              <p>
                Obviously this is a crapload of code just to shunt events around; normally with clutter this is not necessary, but with the X compositing architecture being like it is, we have to roll our own GSource to do the event translation.
              </p>
              <p>
                This brings me back to the beginning, <code>prep_clutter</code>:
              </p>
              <pre class="prettyprint linenums">
GType texture_pixmap_type;
void prep_clutter (int *argc, char ***argv)
{
    clutter_x11_disable_event_retrieval ();
    clutter_init (argc, argv);
    clutter_x11_add_filter (event_filter, NULL);
    
    if (getenv ("NO_TFP"))
        texture_pixmap_type = CLUTTER_X11_TYPE_TEXTURE_PIXMAP;
    else
        texture_pixmap_type = CLUTTER_GLX_TYPE_TEXTURE_PIXMAP;
}
              </pre>
              <p>
                Here we see that you have to turn off event retrieval before calling clutter_init. Then, we tell Clutter to call a event_filter whenever it gets an X event. I'll get back to that function in a minute.
              </p>
            </section>
            <section id="OpenGL">
              <div class="page-header">
                <h1>OpenGL</h1>
              </div>
              <p>
                I suppose that this is as good a time as any to speak of getting window contents into OpenGL. The basic idea is that since we're already storing all of the window's pixels into a backing pixmap (because we are redirecting all output), we don't actually need to transfer the pixels back over the wire to the compositor to have the compositor show the window on the screen. There is a GLX extension, <a href="http://www.opengl.org/registry/specs/EXT/texture_from_pixmap.txt">texture from pixmap</a> or TFP, which tells the libGL implementation to get a texture's contents from a pixmap that it already knows about, automatically updating when the pixmap updates.
              </p>
              <p>
                I digress for a moment to mention something that I did not know when I was getting into all of this. There are two kinds of GLX rendering, direct and indirect. Perhaps you recall these words from running glxinfo to see whether your GL implementation has hardware acceleration or not. In fact, direct vs. indirect exists on a different axis as accelerated vs. software rendering. What "indirect rendering" means is that instead of talking directly to the graphics card through the kernel, a GL application is sending all of its commands over the wire to the X server, which then does the rendering.
              </p>
              <p>
                But that server-side rendering may be accelerated; indeed, that was the whole point of <a href="http://en.wikipedia.org/wiki/AIGLX">AIGLX</a>. Technically, with free drivers, this is implemented via having the server's GLX rendering use the same DRI library as libGL does when doing direct rendering. It is the DRI library which does the accelerated communication with the hardware-specific kernel module (the DRM module).
              </p>
              <p>
                Indirect rendering is slower, however, and it is advantageous to use direct rendering when possible. The problem comes when wanting to use TFP and direct rendering; if I want to bind a GL texture to a pixmap corresponding to some other application, and I am not going to go through the X server to do so, then obviously the kernel itself has to know about X drawables. If I have a named pixmap open from one process that was created from another process, there needs to be a unified memory manager in the kernel:
              </p>
              <p>
                <blockquote>
                  <p>
                   It's a crude approximation but the most crucial difference between the nvidia architecture and DRI/DRM is that nvidia actually have a memory manager - and a unified one at that. Without a memory manager it's impossible to allocate offscreen buffers (hence, no pbuffers or fbos) and without a unified memory manager it's impossible to reconcile 2D and 3D operations (hence no redirected Direct Rendering). The Accelerated Indirect GLX feature that the freetards were busy raving about is an endless source of confusion - and ultimately a hack to workaround their lack of a memory manager.
                  </p>
                  <small>
                    Linux Hater
                    <cite title="Source Title">
                      in
                      <a href="http://linuxhaters.blogspot.be/2008/06/nitty-gritty-shit-on-open-source.html"> his blog post</a>
                    </cite>
                  </small>
                </blockquote>
              </p>
              <p>
                Anyway. You can't do direct TFP with free drivers, is the conclusion of that digression. That's OK, because you can always force indirect rendering via setting LIBGL_ALWAYS_INDIRECT=1 in your environment. But you can't do <a href="https://bugs.freedesktop.org/show_bug.cgi?id=16559">indirect rendering in Xephyr</a>, only direct, so it's tough to test out window managers. Fortunately, you can get window contents into clutter without TFP, using the fallbacks -- hence the NO_TFP check in prep_clutter.
              </p>
            </section>
            <section id="Outro">
              <div class="page-header">
                <h1>Outro</h1>
              </div>
              <h3>ánimo, peregrino.</h3>
              <p>
                OK, at this point we're almost there. Here's the event handler:
              </p>
              <pre class="prettyprint linenums">
static ClutterX11FilterReturn
event_filter (XEvent *ev, ClutterEvent *cev, gpointer unused)
{
    switch (ev->type) {
    case CreateNotify:
        window_created (ev->xcreatewindow.window);
        return CLUTTER_X11_FILTER_REMOVE;

    default:
        return CLUTTER_X11_FILTER_CONTINUE;
    }
}
              </pre>
              <p>
                It's pretty simple, an X event is a tagged union. We respond to the <code>CreateNotify</code> events, which come because we selected for <code>SubstructureNotifyMask</code> on the root window. It turns out we don't need any more events, because clutter handles the rest:
              </p>
              <pre class="prettyprint linenums">
static void
window_created (Window w)
{
    XWindowAttributes attr;    
    ClutterActor *tex;

    if (w == overlay)
        return;

    XGetWindowAttributes (dpy, w, &amp;attr);
    if (attr.class == InputOnly)
        return;
    
    tex = g_object_new (texture_pixmap_type, "window", w,
                        "automatic-updates", TRUE, NULL);

    g_signal_connect (tex, "notify::mapped",
                      G_CALLBACK (window_mapped_changed), NULL);
    g_signal_connect (tex, "notify::window-x",
                      G_CALLBACK (window_position_changed), NULL);
    g_signal_connect (tex, "notify::window-y",
                      G_CALLBACK (window_position_changed), NULL);

    {
        gint mapped, destroyed;
        g_object_get (tex, "mapped", &amp;mapped, NULL);
        if (mapped)
            window_mapped_changed (tex, NULL, NULL);
    }
}
              </pre>
              <p>
                Once we create the window, Clutter will listen for changes in its state -- resizes, maps or unmaps, and ultimately its destruction. (Or at least it will, once <a href="http://bugzilla.o-hand.com/show_bug.cgi?id=1020">#1020</a> is applied.) Here we connect with the minimum bits necessary to make a window usable. Finally, the functions to show, hide, and resize windows:
              </p>
              <pre class="prettyprint linenums">
static void
window_position_changed (ClutterActor *tex, GParamSpec *pspec, gpointer unused)
{
    gint x, y, window_x, window_y;
    g_object_get (tex, "x", &amp;x, "y", &amp;y, "window-x", &amp;window_x,
                  "window-y", &amp;window_y, NULL);
    if (x != window_x || y != window_y)
        clutter_actor_set_position (tex, window_x, window_y);
}
              </pre>
              <pre class="prettyprint linenums">
static void
window_mapped_changed (ClutterActor *tex, GParamSpec *pspec, gpointer unused)
{
    gint mapped;
    g_object_get (tex, "mapped", &amp;mapped, NULL);

    if (mapped){
        clutter_container_add_actor (CLUTTER_CONTAINER (stage), tex);
        clutter_actor_show (tex);
        window_position_changed (tex, NULL, NULL);
    } else {
        clutter_container_remove_actor (CLUTTER_CONTAINER (stage), tex);
    }
}
              </pre>
              <h3>final notes</h3>
              <p>
                Code is <a href="http://wingolog.org/pub/mini-clutter-wm.c">here</a>, compile as:
              </p>
              <p>
                <code>gcc `pkg-config --cflags --libs clutter-glx-0.8` \
     -o mini-clutter-wm mini-clutter-wm.c</code>
              </p>
              <p>
                You might want to run it in a Xephyr; do it with the script <a href="http://wingolog.org/pub/run-xephyr">here</a>:
              </p>
              <p>
                <code>./run-xephyr ./mini-clutter-wm</code>
              </p>
              <p>
                <blockquote>
                  <p>
                   So ideally, "I switched to a new window manager" doesh't mean "my screen has some different widgets on it now". It means "I'm looking at the screen with new eyes."
                  </p>
                  <small>
                    Joey Hess
                  </small>
                </blockquote>
              </p>
              <p>
                This blog is already way too long, so I'll revisit interface concepts at some point in the future. For now I just wanted to pull together this knowledge in one place. Happy hacking!
              </p>
            </section>
    			</div>
			</div>
		</div>

		<script src="http://code.jquery.com/jquery-latest.js"></script>
    <script type="text/javascript" src="assets/js/prettify.js"></script>
		<script src="assets/js/bootstrap.min.js"></script>
	</body>
</html>